package com.wechat.pay.contrib.apache.httpclient.auth;

import com.wechat.pay.contrib.apache.httpclient.Credentials;
import com.wechat.pay.contrib.apache.httpclient.WechatPayUploadHttpPost;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.client.methods.HttpRequestWrapper;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;

public class WechatPay2Credentials implements Credentials {

    private static final Logger log = LoggerFactory.getLogger(WechatPay2Credentials.class);

    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final SecureRandom RANDOM = new SecureRandom();
    protected String merchantId;
    protected Signer signer;

    public WechatPay2Credentials(String merchantId, Signer signer) {
        this.merchantId = merchantId;
        this.signer = signer;
    }

    public String getMerchantId() {
        return merchantId;
    }

    /**
     * 生成时间戳, 单位: s;
     *
     * @return 时间戳
     */
    protected long generateTimestamp() {
        return System.currentTimeMillis() / 1000;
    }

    /**
     * 生成随机字符串
     *
     * @return 随机字符串
     */
    protected String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }

    /**
     * 获取认证类型, WECHATPAY2-SHA256-RSA2048
     *
     * @return 认证类型, 目前为WECHATPAY2-SHA256-RSA2048, 截止2021年6月3日官方公布
     */
    @Override
    public final String getSchema() {
        return "WECHATPAY2-SHA256-RSA2048";
    }

    /**
     * 获取签名信息
     *
     * @param request request对象, 用于获取Method, URL, body(如果有)
     * @return 签名信息
     * @throws IOException 异常
     */
    @Override
    public final String getToken(HttpRequestWrapper request) throws IOException {
        String nonceStr = generateNonceStr();
        long timestamp = generateTimestamp();

        String message = buildMessage(nonceStr, timestamp, request);
        log.debug("authorization message=[{}]", message);

        Signer.SignatureResult signature = signer.sign(message.getBytes(StandardCharsets.UTF_8));

        String token = "mchid=\"" + getMerchantId() + "\"," + "nonce_str=\"" + nonceStr + "\"," + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + signature.certificateSerialNumber + "\"," + "signature=\"" + signature.sign + "\"";
        log.debug("authorization token=[{}]", token);

        return token;
    }

    protected final String buildMessage(String nonce, long timestamp, HttpRequestWrapper request) throws IOException {
        URI uri = request.getURI();
        String canonicalUrl = uri.getRawPath();
        if (uri.getQuery() != null) {
            canonicalUrl += "?" + uri.getRawQuery();
        }

        String body = "";
        // PATCH, POST, PUT
        //这里调用getOriginal()是为了获取真正的request对象, 这个request是wrapper对象;
        if (request.getOriginal() instanceof WechatPayUploadHttpPost) {
            //如果上传谋体信息则获取其meta数据,参考https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter2_1_1.shtml;
            body = ((WechatPayUploadHttpPost) request.getOriginal()).getMeta();
        } else if (request instanceof HttpEntityEnclosingRequest) {
            //如果属于HttpEntityEnclosingRequest, 则是带有entity的;
            body = EntityUtils.toString(((HttpEntityEnclosingRequest) request).getEntity(), StandardCharsets.UTF_8);
        }

        return request.getRequestLine().getMethod() + "\n" + canonicalUrl + "\n" + timestamp + "\n" + nonce + "\n" + body + "\n";
    }

}
